Skip to content

feat(devops): add Husky pre-commit hooks for linting and type checkin… - #676

Open
Venrable18 wants to merge 1 commit into
ritik4ever:mainfrom
Venrable18:feature/640-pre-commit-hooks
Open

feat(devops): add Husky pre-commit hooks for linting and type checkin…#676
Venrable18 wants to merge 1 commit into
ritik4ever:mainfrom
Venrable18:feature/640-pre-commit-hooks

Conversation

@Venrable18

@Venrable18 Venrable18 commented Jul 28, 2026

Copy link
Copy Markdown

Closes #640


All acceptance criteria met:

✅ Hook runs < 20 seconds - Completed in 2.264s
✅ Bypass documented (--no-verify) - Added to CONTRIBUTING.md
✅ Setup in CONTRIBUTING.md - Full documentation added

Implementation summary:

Added husky and lint-staged to root package.json
Configured lint-staged to run ESLint, Prettier, and TypeScript checks on backend//*.{ts,tsx} and frontend//.{ts,tsx}
Configured cargo clippy for contracts/**/
.rs
Updated CONTRIBUTING.md with hook documentation and bypass instructions
Verified performance: 2.3s for typical changes
Screenshot 2026-07-28 at 10 59 22 pm

Summary by CodeRabbit

  • Documentation

    • Added guidance on pre-commit checks, including how to bypass them when necessary.
  • Chores

    • Added automated checks for staged TypeScript, TSX, and Rust files, including linting, formatting, type checking, and Rust quality checks.
    • Improved consistency and readability of backend code without changing application behavior.

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

@Venrable18 is attempting to deploy a commit to the ritik4ever's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Husky/lint-staged pre-commit checks and related contributor documentation. Backend middleware, filtering, health, pagination, response, error, and logging code is reformatted without described runtime changes.

Changes

Pre-commit tooling and backend formatting

Layer / File(s) Summary
Pre-commit checks and documentation
package.json, CONTRIBUTING.md
Adds Husky and lint-staged configuration for TypeScript/TSX and Rust checks, with documentation for hook behavior and bypassing hooks.
Backend structure and formatting
backend/src/index.ts
Reformats middleware, rate limiting, campaign filters, health responses, pagination, error handling, logging, and related response blocks while preserving described behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: emeditweb

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding Husky pre-commit hooks for linting and type checking.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@Venrable18 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
backend/src/index.ts (1)

911-912: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the stray test comments.

These debug artifacts are unrelated to the formatting change and may confuse future maintainers.

Proposed cleanup
-// test
-// test
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/index.ts` around lines 911 - 912, Remove the two stray "// test"
comments from the affected code in index.ts, leaving the surrounding formatting
change and implementation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/index.ts`:
- Around line 134-136: Update the production setup in the app initialization
around apiKeyAuthMiddleware so authentication fails closed when API_KEYS is
missing. Require API_KEYS during production startup or ensure the middleware
rejects every request without configured keys, while preserving normal
authenticated behavior when keys are present.
- Around line 361-363: Update the health-check details in the surrounding
status-building logic so a configured config.sorobanRpcUrl is not described as
“Soroban RPC reachable” without an actual connectivity result. Use the existing
RPC reachability check or report only configuration status, preserving the
unconfigured message when no URL is provided.

In `@package.json`:
- Around line 43-48: Update the lint-staged compiler and Cargo clippy entries to
use filename-agnostic JavaScript functions or argument-ignoring wrapper scripts,
so matched filenames are not appended to `tsc` or `cargo clippy`; preserve the
existing backend, frontend, and contracts working-directory commands and strict
clippy warnings.

---

Nitpick comments:
In `@backend/src/index.ts`:
- Around line 911-912: Remove the two stray "// test" comments from the affected
code in index.ts, leaving the surrounding formatting change and implementation
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 929ccc79-c321-4bee-a9ea-fca971eb8c11

📥 Commits

Reviewing files that changed from the base of the PR and between 10f827c and 117bb4b.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • CONTRIBUTING.md
  • backend/src/index.ts
  • package.json

Comment thread backend/src/index.ts
Comment on lines +134 to 136
if (process.env.NODE_ENV === 'production') {
app.use(apiKeyAuthMiddleware);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when production API keys are missing.

backend/src/middleware/apiKeyAuth.ts accepts any Bearer token when API_KEYS is empty. Since this file mounts that middleware in production, a deployment missing API_KEYS has no effective authentication. Require the variable during production startup or reject requests when it is absent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/index.ts` around lines 134 - 136, Update the production setup in
the app initialization around apiKeyAuthMiddleware so authentication fails
closed when API_KEYS is missing. Require API_KEYS during production startup or
ensure the middleware rejects every request without configured keys, while
preserving normal authenticated behavior when keys are present.

Comment thread backend/src/index.ts
Comment on lines +361 to +363
details: config.sorobanRpcUrl
? 'Soroban RPC reachable'
: 'Soroban RPC URL not configured',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not report a configured RPC as reachable.

This condition only checks whether config.sorobanRpcUrl exists; it performs no connectivity check. A configured but unavailable RPC will be reported as reachable, misleading health checks and monitoring.

Proposed minimal fix
-            ? 'Soroban RPC reachable'
+            ? 'Soroban RPC configured'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
details: config.sorobanRpcUrl
? 'Soroban RPC reachable'
: 'Soroban RPC URL not configured',
details: config.sorobanRpcUrl
? 'Soroban RPC configured'
: 'Soroban RPC URL not configured',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/index.ts` around lines 361 - 363, Update the health-check details
in the surrounding status-building logic so a configured config.sorobanRpcUrl is
not described as “Soroban RPC reachable” without an actual connectivity result.
Use the existing RPC reachability check or report only configuration status,
preserving the unconfigured message when no URL is provided.

Comment thread package.json
Comment on lines +43 to +48
"cd backend && tsc --noEmit"
],
"frontend/**/*.{ts,tsx}": [
"cd frontend && eslint --fix",
"prettier --write",
"cd frontend && tsc --noEmit"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Run in a disposable worktree with representative staged files.
npx lint-staged --debug 2>&1 | tee /tmp/lint-staged-debug.log
grep -E 'tsc --noEmit|cargo clippy' /tmp/lint-staged-debug.log

Repository: ritik4ever/stellar-goal-vault

Length of output: 159


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "package.json:"
if [ -f package.json ]; then
  cat -n package.json | sed -n '1,100p'
else
  echo "package.json not found"
fi

echo
echo "lint-staged config references:"
grep -RIn '"lint-staged"|"lintStaged"|lint-staged|lintStaged' package.json pnpm-lock.yaml package-lock.json yarn.lock 2>/dev/null | sed -n '1,160p' || true

echo
echo "TypeScript config files:"
fd -a 'tsconfig.*json$|tsconfig' . | sed 's#^\./##' | sort | head -80

echo
echo "Rust files:"
git ls-files | grep -E '(^|/)Cargo\.toml$|\.rs$' | head -100

Repository: ritik4ever/stellar-goal-vault

Length of output: 2751


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
# Deterministic model of lint-staged string task command:
# each matched string command is appended with the list of filenames.
commands = [
    "cd backend && tsc --noEmit",
    "cd frontend && tsc --noEmit",
    "cd contracts && cargo clippy -- -D warnings",
]
files = ["backend/src/foo.ts", "frontend/src/bar.tsx", "contracts/src/lib.rs"]

for cmd in commands:
    full = f"{cmd} { ' '.join(files) }"
    print(full)
PY

echo
echo "TypeScript configuration snippets:"
for f in backend/tsconfig.json frontend/tsconfig.json tsconfig.json frontend/tsconfig.node.json frontend/tsconfig.test.json backend/tsconfig.eslint.json; do
  if [ -f "$f" ]; then
    echo "--- $f"
    python3 - <<PY "$f"
import json, sys
p=sys.argv[1]
try:
    data=json.load(open(p))
except Exception as e:
    print(f"error: {e}")
    raise
if isinstance(data, dict):
    for k in ["compilerOptions","extends","include","exclude","references"]:
        if k in data:
            print(k, "=>", data[k])
else:
    print(data)
PY
  fi
done

echo
echo "lockfile lint-staged version:"
for f in package-lock.json pnpm-lock.yaml yarn.lock; do
  [ -f "$f" ] && { echo "--- $f"; grep -n "lint-staged" "$f" | sed -n '1,80p'; }
done

Repository: ritik4ever/stellar-goal-vault

Length of output: 1947


🌐 Web query:

lint-staged string tasks append staged file names lint-staged documentation

💡 Result:

By default, lint-staged automatically appends the list of matched staged files (passed as absolute paths) to the end of your configured command string [1][2][3]. For example, if you configure a task like this: "*.js": "prettier --write" And you have staged files named file-1.js and file-2.js, lint-staged will execute the following command: prettier --write /absolute/path/to/file-1.js /absolute/path/to/file-2.js [1][3][4] Key points to remember: 1. Automatic Appending: You do not need to specify where the file names go in a standard string command; lint-staged handles this for you [1][4]. If you include a path (e.g., "prettier --write."), lint-staged will append the staged files after that path, which may cause unexpected behavior [4]. 2. Function Syntax: When using the advanced JavaScript function syntax in your configuration, lint-staged does not automatically append the file names [1][5]. In these cases, you are responsible for manually including the staged files in your command string or array by using the argument provided to the function [1][3]. 3. Command Length: Because lint-staged appends these files as arguments, very long lists of files might exceed system limits [5]. lint-staged attempts to mitigate this by automatically splitting the list of files into chunks and running the command multiple times [5]. You can control this behavior with the --max-arg-length option if necessary [5].

Citations:


🌐 Web query:

"project" "file names" TypeScript tsc command line compiler rejects project mode filenames

💡 Result:

The TypeScript compiler (tsc) does not have a hard-coded prohibition against specific project filenames in "project mode" (invoked via --project or --build), but it does have specific behavioral requirements and limitations that can cause errors or unexpected rejection of certain files or paths [1][2][3][4]. Common reasons for issues often mistaken for "rejection" include: 1. Filename Parsing and Path Issues: When using tsc --project, if the path to your project contains spaces, the compiler may incorrectly split the path and attempt to interpret the latter part of the path as a separate source file, triggering error TS5042 (option 'project' cannot be mixed with source files) [1]. 2. Extension and Directory Resolution: - Files ending in.jsonc may be incorrectly treated as directories by certain build commands, leading to errors where tsc attempts to append /tsconfig.json to the path [3]. - If you provide a custom configuration filename that does not end in.json or.jsonc, or if the compiler is configured to look for specific naming conventions, it may fail to locate the project file correctly [3]. 3. File Naming Collisions: The TypeScript Language Server can fail to respect project configuration if source files in the project share the same name but differ only by extension (e.g., index.ts and index.tsx residing in the same directory) [2]. 4. Build Mode vs. Project Mode: Using --project (or -p) is fundamentally different from passing a list of files [1]. Mixing these modes—for example, passing a project file and additional source files on the same command line—is not supported and will be rejected [1]. Similarly, --build (tsc -b) has specific requirements for project configuration [5][4]. To avoid these issues: - Ensure project paths and filenames contain no spaces [1]. - Use consistent, standard extensions (.json or.jsonc) for your configuration files [3]. - Avoid mixing --project or --build modes with explicit source file lists on the command line [1]. - Ensure that source files within the project have unique names if possible, particularly when dealing with.ts and.tsx variants in the same scope [2].

Citations:


🌐 Web query:

Cargo CLI -- separator unknown option after separator passed to subcommand

💡 Result:

The double-dash separator (--) in the Cargo CLI is used to distinguish between arguments intended for Cargo itself and arguments intended for the underlying process or tool being invoked (such as a compiled binary, a test harness, or the compiler) [1][2][3]. If you receive an "unknown option" error after the -- separator, it typically means one of the following: 1. Misplaced Arguments: You may be placing arguments intended for Cargo after the -- separator. Arguments placed after -- are passed directly to the sub-process [2][3]. If those arguments contain flags that look like Cargo options (e.g., --verbose), Cargo will not parse them, but the receiving tool might not understand them either, or the CLI parser may still flag them if they are improperly formatted [1][4]. 2. Tool-Specific Argument Parsing: Many tools invoked by Cargo (like test runners or benchmarks) have their own internal argument parsers [4]. If you pass an option that the target tool does not recognize, the error message may originate from that tool rather than Cargo [4]. For example, when running cargo bench or cargo test, arguments after the -- are passed to the test/benchmark harness [4]. Providing an invalid flag to that harness will result in an "unknown option" error [4]. 3. Correct Usage: Ensure that all flags intended for Cargo (such as -p, --release, or --bin) are placed before the -- separator [1][2]. Only pass arguments intended for the final executable or compiler after the -- [2][3]. Example: If you want to run a binary with the flag -r: - Correct: cargo run -- -r [1] - Incorrect: cargo run -r -- (where -r is for the binary) [1] If you believe the option is valid and should be supported by Cargo, ensure it is not a typo or an unstable flag that requires -Z [5][6]. You can verify the valid arguments for a command by running cargo <command> --help [5][7].

Citations:


Run the compiler and Cargo clippy as filename-agnostic tasks.

With lint-staged string tasks, matched-file paths are appended after the command, so cd backend && tsc --noEmit and cd frontend && tsc --noEmit are executed with source filenames appended alongside project defaults, and cd contracts && cargo clippy -- -D warnings receives those paths after Cargo’s --, where they can be interpreted as rustc flags. Use JS function tasks that ignore filenames, or wrap the checks in scripts that ignore args and run the project-level commands.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 43 - 48, Update the lint-staged compiler and Cargo
clippy entries to use filename-agnostic JavaScript functions or
argument-ignoring wrapper scripts, so matched filenames are not appended to
`tsc` or `cargo clippy`; preserve the existing backend, frontend, and contracts
working-directory commands and strict clippy warnings.

@ritik4ever

Copy link
Copy Markdown
Owner

Hi @Venrable18,

This PR could not be merged because it has merge conflicts with the target branch.

Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged.

Thank you!

1 similar comment
@ritik4ever

Copy link
Copy Markdown
Owner

Hi @Venrable18,

This PR could not be merged because it has merge conflicts with the target branch.

Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add pre-commit hooks for linting and type checking

2 participants